package com.chris.core.socket.netty.handler;

import com.chris.core.socket.netty.dto.NettyAttributeMapDTO;
import com.chris.core.socket.netty.dto.SocketChannelMapDTO;
import com.chris.core.socket.netty.util.NettyRunTimeUtil;
import com.chris.core.socket.netty.util.NettyServerUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.DefaultEventLoopGroup;
import io.netty.util.Attribute;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.EventExecutorGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.UUID;
import java.util.concurrent.Callable;

import static com.chris.core.socket.netty.util.NettyRunTimeUtil.*;


/**
 * 自定义netty 服务端 handler
 */
public class StringServerHandler extends ChannelInboundHandlerAdapter {

    
    private Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * 线程池
     * 异步线程池，由hanlder使用
     * 作为重负载操作，比如IO ，如 100路文件 文件同时上传
     */
    public final static EventExecutorGroup executoGroup = new DefaultEventLoopGroup(30);



    /**
     * 读取客户端发送消息
     * @param ctx 上下文对象 ： 管道piline , 通道, 客户端地址
     * @param msg 客户端发送数据
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

       // super.channelRead(ctx,msg);
        //注意区别 ：byteBuffer(nio) ByteBuf (netty)
       // ByteBuf byteBuf =(ByteBuf)msg;
       log.debug("获取客户端发送数据：" +msg.toString());

        //客户端发来read-ping,回复pong,  wrtie-ping 不回复
       // if (msg.equals("read-ping"))
       //     ctx.writeAndFlush("pong\r\n");


      //  String tip= byteBuf.toString(CharsetUtil.UTF_8);
       // String tip=(String) msg;
        //-----群发----
        /*
        for (Channel channel:channels
             ) {
            if (channel != ctx.channel())
                channel.writeAndFlush(Unpooled.copiedBuffer("[客户端] 发送消息：" + tip+"\r\n",StandardCharsets.UTF_8));
            else
                channel.writeAndFlush(Unpooled.copiedBuffer("[客户端] 发送消息成功 \r\n" ,StandardCharsets.UTF_8));
        }

         */
        //---------
        //方法1 异步执行 eventLoop 自带单线程
        /*
        ctx.channel().eventLoop().execute(new Runnable() {
            @Override
            public void run() {

            }
        });

         */
        if (msg.equals(_cmdUpFile)) {
            //截获上传文件命令
            log.debug("截获上传文件命令");
        }

        //方法2 自定义 线程池
        executoGroup.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                //---------------

                NettyAttributeMapDTO attribute = getAttribute(ctx.channel());
              //  log.debug("获取客户端["+attribute.getId()+"]发送数据：" +msg.toString());

                //-------------
                return null;
            }
        });

        //传递给下一个pinline
        super.channelRead(ctx,msg);
    }

    /**
     * channel被加入事件
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        //  super.handlerAdded(ctx);
        if (getOnlineCount()>1000000)
        {
            ctx.channel();
            throw  new Exception("连接数超过限制");
            //  ctx.close();
        }

        Channel channel = ctx.channel();

        //--------------处理Attribute-------------------
        Attribute<NettyAttributeMapDTO> attr = channel.attr(NETTY_CHANNEL_KEY);
        NettyAttributeMapDTO attribute = attr.get();
        if (attribute == null) {
            String uuid = UUID.randomUUID().toString();
            //------------放入Attribute
            NettyAttributeMapDTO dto = new NettyAttributeMapDTO(uuid,"NettySocket");
            attribute = attr.setIfAbsent(dto);
            //-------------放入ChannelMap
            SocketChannelMapDTO socketChannelMap = new SocketChannelMapDTO(uuid,"NettySocket", channel);
            SocketChannelMap.put(uuid, socketChannelMap);
            //--------------
            addOnlineCount();
           // log.debug("客户端["+uuid+"]新增 地址："+channel.remoteAddress()+ " 总客户端数："+getOnlineCount());
        } else {

        }
        //----------------------------------------------------


    }



    /**
     * 客户端数据读取完毕
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
       // super.channelReadComplete(ctx);
      //  ctx.writeAndFlush(Unpooled.copiedBuffer("服务端读取完毕\r\n".getBytes(StandardCharsets.UTF_8)));
    }

    /**
     * 异常处理
     * 一般是关闭通道
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
        log.debug("服务端通道捕获异常 客户端地址:"+ctx.channel().remoteAddress() +" 问题:"+cause.toString() )  ;
    }

    /**
     * 当通道就绪
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {


        Channel channel = ctx.channel();
        NettyAttributeMapDTO dto = getAttribute(channel);
        // super.channelActive(ctx);
        // channel.writeAndFlush("全局通知-》有客户端上线：地址："+channel.remoteAddress()+ " 总客户端数："+getOnlineCount());
        channel.writeAndFlush("欢迎上线!" + NettyRunTimeUtil.runTimeBreakMark);
        log.debug("客户端[" + dto.getId() + "]上线 地址：" + channel.localAddress() +" |"+channel.remoteAddress() + " 总客户端数：" + getOnlineCount());
    }

    /**
     * 通道非活动状态
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //super.channelInactive(ctx);
        Channel channel = ctx.channel();
        NettyAttributeMapDTO dto= getAttribute(channel);
        // super.channelActive(ctx);
       // channels.writeAndFlush("全局通知-》有客户端下线：地址："+channel.remoteAddress()+ " 总客户端数："+getOnlineCount());
        log.debug("客户端["+dto.getId()+"]下线 地址："+channel.remoteAddress()+ " 总客户端数："+getOnlineCount());
    }

    /**
     * channel被移除
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        // super.handlerRemoved(ctx);
        Channel channel = ctx.channel();

        //加入全局数组 ，不需要remove ,自动完成了 remove动作了
        //channels.remove(channel);

        NettyAttributeMapDTO attribute = getAttribute(channel);
        if (attribute != null) {
            SocketChannelMap.remove(attribute.getId());
            //--------------
            subOnlineCount();
            log.debug("客户端["+attribute.getId()+"]离开 地址："+ctx.channel().remoteAddress()+ " 总客户端数："+getOnlineCount());
        }

    }

    /**
     * 获取Channel绑定信息
     * @param channel
     * @return
     */
    public NettyAttributeMapDTO getAttribute(Channel channel)
    {
        Attribute<NettyAttributeMapDTO> attr = channel.attr(NETTY_CHANNEL_KEY);
        NettyAttributeMapDTO attribute = attr.get();
        return attribute;
    }
}
